package com.zyr.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson2.JSON;
import com.zyr.constraint.AuthConstants;
import com.zyr.filter.TokenTranslationFilter;
import com.zyr.model.Result;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;

/**
 * @author 张雨润
 * @date 2024/7/28 下午1:25
 * @Description
 */
@Slf4j
@Configuration
@EnableMethodSecurity
public class ResourceServerConfig {
    @Resource
    private TokenTranslationFilter tokenTranslationFilter;

    @Bean
    public SecurityFilterChain resourceFilterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(tokenTranslationFilter, UsernamePasswordAuthenticationFilter.class);
        // 由于使用token认证，关闭一跨域请求伪造，csrf防御，session管理
        http.csrf(AbstractHttpConfigurer::disable)
                .cors(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        //
        // 配置处理携带token但权限不足的请求
        http.exceptionHandling(e -> {
            e.authenticationEntryPoint(authenticationEntryPoint()) // 处理没有携带token的请求
                    .accessDeniedHandler(accessDeniedHandler()); // 处理携带token，但是权限不足的请求
        });
        // 资源放行路径
        http.authorizeHttpRequests(auth -> auth
                // 资源放行路径
                .requestMatchers("/test").permitAll()
                .anyRequest().authenticated());
        http.addFilterBefore(tokenTranslationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    /**
     * 未认证处理
     * @return
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            String localizedMessage = "未认证，需要登录";// authException.getLocalizedMessage();
            HashMap<String, Object> result = new HashMap<>();
            result.put("code", -1);
            result.put("msg", localizedMessage);
            // 利用fastjson工具，将对象转换成json字符串
            String json = JSON.toJSONString(result);
            // 返回json数据到前端
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().println(json);
        };
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            String res = JSONObject.toJSONString(Result.error(700, "无权限访问，请联系管理员"), SerializerFeature.DisableCircularReferenceDetect);
            response.setContentType("application/json;charset=utf-8");
            ServletOutputStream out = response.getOutputStream();
            out.write(res.getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();
        };
    }
}
